#include <stdio.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

//test 2

//Definations
#define STRLENGTH 256
#define Not_In_Use -1
#define FIFO 1
#define RR 0
#define NotFound 0
#define Found 1
#define true 1
#define false 0
#define Action_Pause 0
#define Action_RemoveFromQue 1
#define PAUSED 0
#define RUNNING 1
#define TERMINATED 2
//Define Job Structure
typedef struct {
	int JOBID; // must initialise to 0 - 255 at the beginning
	int PID;
	int PPID; // Christ wanna add
	char FileName[256]; // modified by Guili
	char Argument[200][256]; // Guili amended because Argument should be an array of strings
	char Environment[20][256]; // not sure what is this?
	char *Env_VAL_; // added by Guili
	char *Env_VALUE_; // added by Guili
	char *Path_; // added by Guili // this is the path to find the executables
	char Jobname[256]; // added by Guili needed/
	short int Policy; // RR[0] FIFO[1]
	short int Priority;
	short int DefaultQuantum;
	short int RemainingQuantum;
	short int Status;
	short int Existence; // added by Guili -- must initialiesed to 0 at the beginning

}
JOB; //Assume we can have only 255 jobs in the table. If possible we change it to a dynamic array later using malloc.


typedef struct  {
	int QueType;
	int Piority;
	int JOBIDs[20];
	int NumofJobs;
}QueStructure; // QueList can have up to 10 Ques. Each Que can have up to 20 JOBS. Cos MAx MAXQUE=10

//############Global Variable that everyone can use #####################
FILE *fp;
char str[STRLENGTH];
char *strptr;
int TICK = 10;
int QUANTUM = 1;
int MAXPROC = 1;
int MAXQUEUE = 20;
int NumOfTaskInQueue=0; //Keep track of task we have in Que, as we want to load = MAXQUEUE # inside
char *ENV_VAR; // not sure about the default
char *ENV_VALUE; // not sure about the default
char *PATH; // not sure about the default
int job_num = 0; //
int wait_num;// Everytime a wait command is called, please set this
int NumRunningExe=0;
int NumDoneExe_afterWait = 0; // number of Executable done after wait has been called
int WaitStatus=false;
//int i; // use for the counting of arguments in task..  not global...
//int n; // for the use of arguments.. not global
char GlobalEnv[20][256]; // Added by Guili 7 April 2:37pm
int TopPriorityTask[10]; //Store the JOBID  of Top few prioirty task
int RunningTask[10]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};//Store the JOBID  of Top few prioirty task


JOB JOBTable[255];
QueStructure QueList[10];




//   ###########Function ProtoType Declaration###########
//These are just a very rough guideline of the min basic functions that should exist.
//Feel free to improvise


//Functions by GuiLi+Rensha
int nextCommandLine();//Reads & Process the next cmd in file.Return 0 is EOF, 1 if successful
void PrintJOBTable(int NumOfRecords); //DEBUG purpose to print First the first #NumofRecords in JOBTables
int CheckJobStatus (int job_ID); //Return RUNNING or TERMINATED by using WaitPID();

//Functions by Chris
void RunEXE(int JOBID); //unpaused or execute the current exe with jobID.  Remember to run it with the environment specified in JobList
void ExeChildren(int JOBID); //printout the Job's ID child
void pauseExe(int JOB_ID); //Pause the JOBID. Please remember to update the Status in JOBList
void unpauseExe(int JOB_ID); //unpause the Exe. Update status in JOBList
void SetEnv(char *ENV_VAR, char *ENV_VALUE);
void UnsetEnv(char *ENV_VAR);

//Functions by Emmanuel
void RetriveHighestPiority(int NumofProcess); //Retrive the top NumOfProcess that should be running
void PrintHighestPiority(); //Debug function to testprint TopPriorityTask[]
void AddtoQue(int NewJOBID);
void ResetQue(int index);//Reset 1 Que.
void ResetQueList(); //Reset all the Ques in QueList
void PrintAllQues();//Debug function
void PrintQue(int index);//Debug function
void SortQueList(); //Sort the entire QueList in decending order of piority
void DeQue(int JOBID,int Action);
void CompactQue(int QueIndex); //Compact que after any deletion or pause
void CompactRunningTask();////Compact RunningTask after adding/removing stuff from it
int MustWait(); //Determines if we need to wait or not.
int IsItInTopPriorityTask(int JOBID); //Check if a job is in TopPriorityTask
int IsItInRunningTask(int JOBID);
//Common Functions that everyone might use
void NotifyNewTaskAdded(int JOBID); // After a Task command is read, ProcessNextCmd() should call
// this function to notify everyone that theres a new task.
//People like Emmanuel & Chris who needs to be notified that
//a new task has been added, should put their respective code
//handler inside

void NotifyWaitCmd(int waitnumber); //after a Wait # command is read, ProcessNextCmd() should
//call this function t notify everyone


//#########GLOBAL Variables################


int main() {
	int CurrentJob=0;
	int CurrentJOBID=-1;
	
	//Initialize all the Ques etc.
	//@todo
	//wait_num = MAXPROC;
	ResetQueList();

	fp = fopen("first.c", "r"); // need to take care of the name of the input file..
	if (fp == NULL){
		
		fprintf(stderr,"Could not open first.c\nExiting now\n");
		exit(1);
	}

	while(NumRunningExe!=0 || feof(fp)==0){ //Keep running our scheduler until we have Finished all Running process + Process the entire file
		
		while(NumOfTaskInQueue<MAXQUEUE && !feof(fp) && MustWait()==false){ //If we still have space to put task into queue and our file not read finish
			printf("Processed 1 line\n");
			nextCommandLine(); //Load all the task until we fill up MAXQueue
		}
		//At this point we have tried to load all the task into the Que base on the condition of either MAXQUEUE 
		//@todo make sure to satisfy the WAIT command too
		//Loop through all the RunningTask,If its a RR, minus one quantum.. If run out of quantum, deque it. Reset RunningTask[]. Restore its Default Quantum
		for(CurrentJob=0;CurrentJob<10;CurrentJob++){
			CurrentJOBID=RunningTask[CurrentJob];
			if(CurrentJOBID==-1) continue; //Dont wanna process -1 jobs
			if(JOBTable[CurrentJOBID].Policy==RR){ 
				JOBTable[CurrentJOBID].RemainingQuantum--;
				if(JOBTable[CurrentJOBID].RemainingQuantum<=0){ //Run out of Quantum, deque it.
					DeQue(CurrentJOBID,Action_Pause);
					NumRunningExe--;
					RunningTask[CurrentJob]=-1;// Reset it in Running task.	
					JOBTable[CurrentJOBID].RemainingQuantum=JOBTable[CurrentJOBID].DefaultQuantum;
				}
			}
		}		
		CompactRunningTask(); //Comptact RunningTask after adding/removing 
		//Now we want to RetriveHighestPiority of task  into TopPriorityTask[] ]and check if they are running. If they are not running, run them. Any task that are currently but is not in RetriveHighestPiority of task, we wanna pause them.
		RetriveHighestPiority(MAXPROC); //We now have #MAXPROC of top piority TASK that should be running;
		
		for(CurrentJob=0;CurrentJob<10;CurrentJob++){
			CurrentJOBID=RunningTask[CurrentJob];
			//Loop through the Array of RunningTask
			//Check each task that is running should be running, by comparing with TopPriorityTask
			//Anytask that is running, but not in TopPriorityTask, should be DeQue()
			//Any task that is in RunningTask[], but has actually excited, removed it from running task.
			//Any task in TopPriorityTask[] but not in RunninTask we need to run it, increase NumRunningExe;
			//Minus The Quantum for any running task. If Quantum==0; dequeue it.
			if(CurrentJOBID!=-1){ 
				if(CheckJobStatus(CurrentJOBID)==TERMINATED){
					//Any Job that has ben terminated
					//Remove it from queue
					printf("\nJOB(%d) has terminated\n",CurrentJOBID);
					DeQue(CurrentJOBID,Action_RemoveFromQue);
					NumRunningExe--;
					RunningTask[CurrentJob]=-1;// Reset it in Running task.
				}
				else if(IsItInTopPriorityTask(CurrentJOBID)==false){ //Still Running Not in top prioitytask list, deque it
					NumRunningExe--;
					DeQue(CurrentJOBID,Action_Pause);//@todo : Chris function to Pause the task *UPDATE* DeQue will auto call Chris Function to pause it.
					RunningTask[CurrentJob]=-1;// Reset it in Running task.
				}
				
				
			}

		}
		CompactRunningTask(); //Comptact RunningTask after adding/removing 
		
		//Loop through TopPriorityTask, compare with CompactRunningTask. If its not running, RUN IT
		for(CurrentJob=0;CurrentJob<10;CurrentJob++){
			CurrentJOBID=TopPriorityTask[CurrentJob];
			if(CurrentJOBID!=-1){ 
				if(IsItInRunningTask(CurrentJOBID)==false){ //Not in top runningTask. Start It
					NumRunningExe++;
					unpauseExe(CurrentJOBID);//Runs the Exe
					RunningTask[NumRunningExe]=CurrentJOBID;//add it to runningtasklist
				}
				
				
			}
			
		}
	
		usleep(TICK); //Runs the Scheduler every TICK
	}
	//
	PrintJOBTable(3);
	printf("End of loop");
	/*		while (nextCommandLine()!=0);
		PrintJOBTable(5); //Print First 5 Records of JobTable

//sprintf(stdout,"hello Quantum=%d",QUANTUM);

	//JOBTable[0]={.JOBID=0,.PID=100,.Policy=RR,.Priority=10};
	PrintAllQues();
	RetriveHighestPiority(40);
	PrintHighestPiority();
	DeQue(3,Action_Pause);
	DeQue(2,Action_RemoveFromQue);
	DeQue(100,Action_RemoveFromQue);
	DeQue(0,Action_RemoveFromQue);
	PrintAllQues();
	RetriveHighestPiority(40);
	PrintHighestPiority();
	RetriveHighestPiority(3);
	PrintHighestPiority();
usleep(1000000);
printf("test\n");
usleep(1000000);
usleep(1000000);
usleep(1000000);
usleep(1000000);
usleep(1000000);
usleep(1000000);
usleep(1000000);

printf("test\n");
*/







	return 1;

}

int nextCommandLine() {
//char *env;
int k;
int i;
int n;
char name[256];
char arg[256];
int namelength;
int arglength;
int j;


	if (!feof(fp)) {
		fgets(str, STRLENGTH, fp); // this is the same as next command line
		if (!feof(fp)) {
			//printf("%s", str);
			if (str[strlen(str)-1] == '\n')
			{
			//printf("am I here??");
			str[strlen(str)-1] = '\0';
			str[strlen(str)] = '\0';
			}
			//printf("**** %x [%s]\n", str, str);
			strptr = strtok(str, " ");
			// if token = end of line do nothing : i.e move to the new line
			//printf("I am here! \n");
			if (strptr != NULL ) {
				// if token is equal to # do nothing : i.e move to the new line
				if (strcmp(strptr, "#") != 0) {
					// if token != # do the following : check when it is and input to the proper table  then perform token = strtok(NULL, ",");
					// if first one is TICK, set TICK = the number
					if (strcmp(strptr, "tick") == 0) {
						//printf("TICK before modification: %d \n", TICK);
						strptr = strtok(NULL, " ");
						TICK = atoi(strptr);
						//printf("TICK after modification: %d \n", TICK);
					} else {
						// quantum
						if (strcmp(strptr, "quantum") == 0) {
							//printf("quantum before modification: %d \n", QUANTUM);
							strptr = strtok(NULL, " ");
							QUANTUM = atoi(strptr);
							//printf("quantum after modification: %d \n", QUANTUM);
						} else {
							// maxproc
							if (strcmp(strptr, "maxproc") == 0) {
								strptr = strtok(NULL, " ");
								MAXPROC = atoi(strptr);
							} else {
								// max queue
								if (strcmp(strptr, "maxqueue") == 0) {
									strptr = strtok(NULL, " ");
									MAXQUEUE = atoi(strptr);
								} else {
									// setenv
									if (strcmp(strptr, "setenv") == 0) {
										strptr = strtok(NULL, " ");
										ENV_VAR = strptr;
										strptr = strtok(NULL, " ");
										ENV_VALUE = strptr;
										//strcat(env, ENV_VAR);
										//strcat(env, "=");
										//strcat(env, ENV_VALUE);
										SetEnv(ENV_VAR, ENV_VALUE);
										
									} else {
										// unsetenv // need to double check?
										if (strcmp(strptr, "unsetenv") == 0) {
											strptr = strtok(NULL, " ");
											ENV_VAR = strptr;
											//ENV_VALUE = NULL;	// to be confirmed??
											UnsetEnv(ENV_VAR);
										} else {
											if (strcmp(strptr, "path") == 0) {
												strptr = strtok(NULL, " ");
												PATH = strptr;
											} else {
												// wait
												if (strcmp(strptr, "wait") == 0) { // this can be a wait function
													if (strptr != NULL ) {
														strptr = strtok(NULL, " ");
														wait_num = atoi(strptr);
													}
													NotifyWaitCmd(wait_num);
													
												} else 
													{
													// task
													if (strcmp(strptr, "task") == 0) {
														// initialise all the jobs parameters
														JOBTable[job_num].PID = -1;
														JOBTable[job_num].JOBID = job_num;
														JOBTable[job_num].Existence = 1;
														JOBTable[job_num].Priority = 1;
														JOBTable[job_num].Policy = 0;
														JOBTable[job_num].Status=PAUSED;
														JOBTable[job_num].DefaultQuantum = QUANTUM;
														JOBTable[job_num].RemainingQuantum = QUANTUM;
														// What about Status??
														//JOBTable[job_num].Env_VAL_ = ENV_VAR;
														//JOBTable[job_num].Env_VALUE_ = ENV_VAR;
														//JOBTable[job_num].Environment = GlobalEnv; 
														// to set job env
														for (k = 0; k<20; k++)
															strcpy(JOBTable[job_num].Environment[k],GlobalEnv[k]);
														JOBTable[job_num].Path_ = PATH;
														// job name?
														strptr = strtok(NULL, " ");
														// this can be a function of adding task
														///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
														// this is the start of the function of addingTask
														for (i = 0; strptr != NULL && i < 3; i++) {
															//printf("I am here?! \n");
															if (strcmp(strptr, "-p") == 0) {
																strptr = strtok(NULL, " ");
																//printf("am i here? \n");
																if (isdigit(*strptr) != 0 ) {
																	if ((atoi(strptr)) >= 1 &&  (atoi(strptr)) <= 10 ) {
																		JOBTable[job_num].Priority = atoi(strptr);
																	}
																	strptr = strtok(NULL, " ");
																}

															} else {
																if (strcmp(strptr, "-s") == 0) {
																	strptr = strtok(NULL, " ");
																	//printf("am i here? \n");
																	if (strcmp(strptr, "FIFO") == 0 ) {
																		JOBTable[job_num].Policy = 1;
																		strptr = strtok(NULL, " ");
																	} else {
																		if (strcmp(strptr, "RR") == 0 )
																		strptr = strtok(NULL, " ");
																	}
																} else {
																	if (strcmp(strptr, "-q") == 0) {
																		strptr = strtok(NULL, " ");
																		if (isdigit(*strptr) != 0 ) {
																			if (atoi(strptr) > 0) {
																				JOBTable[job_num].DefaultQuantum = atoi(strptr);
																				JOBTable[job_num].RemainingQuantum = atoi(strptr);
																			}
																			strptr = strtok(NULL, " ");
																		}
																	}
																}
															}
														}

														//strcpy[JOBTable[job_num].FileName, strptr]; //correct?
														
														namelength = strlen(strptr);
														for (k = 0; k < namelength; k++)
															name[k] = strptr[k];
														name[k]='\0';
														strcpy(JOBTable[job_num].FileName, name); 
														for (k = 0; k < namelength; k++)
															name[k] = '\0';
														
														strptr = strtok(NULL, " ");

														for (n = 0; strptr!=NULL; n++) 
														{
															arglength = strlen(strptr);
															
															for (k = 0; k <arglength; k++)
																arg[k] = strptr[k];
															arg[k] = '\0';	
															strcpy(JOBTable[job_num].Argument[n], arg); 
															//JOBTable[job_num].Argument[n] = strptr;
															
															for (k = 0; k <arglength; k++)
																arg[k] = '\0';
															strptr = strtok(NULL, " ");
															
															//printf("****** arg %x [%s]\n", strptr);
														}
														//printf("ahhhhhhhhhhhhhhhhhh\n jobtable[%d] Argument[%d] is [%s] \n", job_num, n-1, JOBTable[job_num].Argument[n-1]);
														/*
														printf("\n job 1 is [%s] \n", JOBTable[job_num].FileName);
														printf("\n job 1 existence is [%d] \n", JOBTable[job_num].Existence);
														printf("\n job 1 priority is [%d] \n", JOBTable[job_num].Priority);
														printf("\n job 1 policy is [%d] \n", JOBTable[job_num].Policy);
														printf("\n job 1 DQ is [%d] \n", JOBTable[job_num].DefaultQuantum);
														printf("\n job 1 RQ is [%d] \n", JOBTable[job_num].RemainingQuantum);
														
														for (j = 0; j< n; j++){
														//fflush(NULL);
														printf("\n jobtable[%d] Argument[%d] is [%s] \n", job_num, j, JOBTable[job_num].Argument[j]);
														}
														*/
														NotifyNewTaskAdded(job_num);
														/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
														//end of addingTask
														/////////														
														job_num ++;
														//printf("job 0 is [%s] \n", JOBTable[0].FileName);
													}
												}
											}
										}
									}
								}
							}
						}
					}

				} // end if
			} // end if
		}
		return 1;
	} else {
		fclose(fp);
		return 0;
	}

}



void NotifyWaitCmd(int waitvalue) {
	//To be implemented
}
void NotifyNewTaskAdded(int newJOBID) {
	AddtoQue(newJOBID);
}

void AddtoQue(int NewJOBID) {
	short int FindQueExist=NotFound;
	short int CurrentQueNum;
	int NewJobPiority=JOBTable[NewJOBID].Priority;

	for (CurrentQueNum=0;CurrentQueNum<10;CurrentQueNum++) {//Loop through QueList to see if theres already a que with that piority created
		if (QueList[CurrentQueNum].Piority==NewJobPiority) {//Found a Que with that piority number existing
			FindQueExist=Found;
			break;

		}
	} //End of loop through the Entire QueList

	if (FindQueExist==Found) { //Found an existing que with that priority in the QueList.
		if (QueList[CurrentQueNum].NumofJobs<20) {//If that que already exist + is not full, add the job into that que
			QueList[CurrentQueNum].JOBIDs[QueList[CurrentQueNum].NumofJobs]=NewJOBID;
			QueList[CurrentQueNum].NumofJobs++;
		} else fprintf(stderr,"Que with Piority Exist, but its full!"); //Que Exist But its full, print error
	} else if (FindQueExist==NotFound) {//After looping through the entire  QueList, we we didnt find a Existing Que with piority =NewJobPriority
		int FindFreeQue=NotFound;
		//We wnat to create a new Que
		//find the First Available slot in the QueList
		for (CurrentQueNum=0;CurrentQueNum<10;CurrentQueNum++) {
			if (QueList[CurrentQueNum].QueType==Not_In_Use) {
				FindFreeQue=Found;
				break; //Found an index for a Free Que Slot in QueList
			}
		}
		//CurrentQueNum Now contains the index of the first free slot in quelist
		if (FindFreeQue==Found) { //Found a free que slot in QueList, so add it in now
			QueList[CurrentQueNum].QueType=JOBTable[NewJOBID].Policy;
			QueList[CurrentQueNum].Piority=JOBTable[NewJOBID].Priority;
			QueList[CurrentQueNum].JOBIDs[0]=NewJOBID;
			QueList[CurrentQueNum].NumofJobs=1;

		} else {//Cant find a free que slot in QueList to create new Que.
			fprintf(stderr,"Cant create a new Que");
		}

	}

	SortQueList();
	NumOfTaskInQueue++; //Keep track of the # of task in qeues.
	printf("Added new Task. Total Num in que=%d\n",NumOfTaskInQueue);
}//end of AddtoQue()


void ResetQue(int index) {
	int counter;
	QueList[index].QueType=Not_In_Use;
	QueList[index].Piority=0;
	QueList[index].NumofJobs=0;
	for (counter=0;counter<20;counter++) {
		QueList[index].JOBIDs[counter]=-1;
	}

}

void ResetQueList() {
	int counter;
	for (counter=0;counter<10;counter++) {
		ResetQue(counter);
	}
}

void PrintAllQues() {
	int counter;
	printf("\nPrinting Piority Quetable\n");
	for (counter=0;counter<10;counter++) {
		PrintQue(counter);
	}
}
void PrintQue(int index) {
	int counter;
	printf("Index:%d Que Type:%d,Piority:%d,NumofJobs:%d[",index,QueList[index].QueType, QueList[index].Piority, QueList[index].NumofJobs);
	for (counter=0;counter<20;counter++) {
		printf("%d,",QueList[index].JOBIDs[counter]);
	}
	printf("]\n");
}

void PrintJOBTable(int NumOfRecords) {
	int counter;
	for (counter=0;counter<NumOfRecords;counter++) {
		printf("JOBID- %d & Policy %d , FileName %s Piority-%d\n",JOBTable[counter].JOBID,JOBTable[counter].Policy,JOBTable[counter].FileName,JOBTable[counter].Priority);
	}
}

void SortQueList(){
	short int ChangesMade;
	short int counter=0;
	QueStructure tempQue;
	do{
		ChangesMade=false;
		for(counter=0;counter<9;counter++){
			if(QueList[counter].Piority<QueList[counter+1].Piority){
				tempQue=QueList[counter];
				QueList[counter]=QueList[counter+1];
				QueList[counter+1]=tempQue;
				ChangesMade=true;
			}
		}
	}while(ChangesMade==true);
}

void RetriveHighestPiority(int NumofProcess){ //The the First few NumOfProcess top priority task and store them in TopPriorityTask;
	int CurrentQue=0;
	int counter=0;
	if(NumofProcess>10)NumofProcess=10; //Max top 10 only
	//Reset TopPriorityTask[]
	for(counter=0;counter<10;counter++)TopPriorityTask[counter]=-1;

	counter=0;
	for(CurrentQue=0;CurrentQue<10;CurrentQue++){ //Loop through the entire QueList
		int CurrentJob=0;
		for(CurrentJob=0;CurrentJob<QueList[CurrentQue].NumofJobs;CurrentJob++){
			TopPriorityTask[counter]=QueList[CurrentQue].JOBIDs[CurrentJob];
			counter++;
			//printf("%d\n",QueList[CurrentQue].JOBIDs[CurrentJob]);
			NumofProcess--;
			if(NumofProcess==0) return; //We have printed out the required Top Piority NumofProcess
		}
	}
}
void PrintHighestPiority(){
	int counter;
	printf("\nTop Number process\n");
	for(counter=0;counter<10;counter++){
		if(TopPriorityTask[counter]!=-1){
			printf("%d\n",TopPriorityTask[counter]);

		}
	}
}

void DeQue(int JOBID,int Action){ //Eg DeQue(2,Action_RemoveFromQue);
	int CurrentQue;
	int CurrentJob;
	int FindQue=NotFound;
	for(CurrentQue=0;CurrentQue<10;CurrentQue++){

		for(CurrentJob=0;CurrentJob<QueList[CurrentQue].NumofJobs;CurrentJob++){
			if(QueList[CurrentQue].JOBIDs[CurrentJob]==JOBID){
				FindQue=Found;
				break;
			}

		}
		if(FindQue==Found) break; //We found the JOb at QueList[CurrentQue].JOBIDs[CurrentJob]

	}

	if(FindQue==Found){//We found the JOb at QueList[CurrentQue].JOBIDs[CurrentJob]
		if(Action==Action_Pause){ //Wanna Pause the Que
			if(QueList[CurrentQue].QueType==FIFO){
				printf("Pause FIFO JOBID %d\n",QueList[CurrentQue].JOBIDs[CurrentJob]);
				//@todo Call chris function to pause
			}
			else if(QueList[CurrentQue].QueType==RR){ //Pause a RR task and shift it back to end of que
				printf("Pause RR JOBID %d\n",QueList[CurrentQue].JOBIDs[CurrentJob]);

				//@todo Call Chris Function to Pause;
				//Shift JOB to end of Que
				QueList[CurrentQue].JOBIDs[QueList[CurrentQue].NumofJobs]=QueList[CurrentQue].JOBIDs[CurrentJob];
				QueList[CurrentQue].JOBIDs[CurrentJob]=-1; //Reset Current Position to empty
				//@todo Call function to compact JOBIDs[]]
				CompactQue(CurrentQue);

			}

		}

		else if(Action==Action_RemoveFromQue){
			NumOfTaskInQueue--; //Reduce the # of task in que
			printf("Removed JOBID %d\n",QueList[CurrentQue].JOBIDs[CurrentJob]);
			QueList[CurrentQue].JOBIDs[CurrentJob]=-1; //Reset Current Position to empty
			QueList[CurrentQue].NumofJobs--;
			if(QueList[CurrentQue].NumofJobs==0){//Empty Que , so lets reset it and rearrange baby
				ResetQue(CurrentQue);
				SortQueList();//Lets Rearrange

			}else{
				//Not empty
				//@todoCall function to compact JOBIDs[]]
				CompactQue(CurrentQue);
			}
		}


	}
	else if (FindQue==NotFound) fprintf(stderr,"Cant Find JOB %d TO DeQue\n",JOBID); //Que Exist But its full, print error


}

void CompactQue(int QueIndex){
	int changes=false;
	int CurrentJob;
	do{
		changes=false;
		for(CurrentJob=0;CurrentJob<19;CurrentJob++){
			if(QueList[QueIndex].JOBIDs[CurrentJob]==-1 && QueList[QueIndex].JOBIDs[CurrentJob+1]!=-1){
				int tempJobID;
				//Swap
				tempJobID=QueList[QueIndex].JOBIDs[CurrentJob];
				QueList[QueIndex].JOBIDs[CurrentJob]=QueList[QueIndex].JOBIDs[CurrentJob+1];
				QueList[QueIndex].JOBIDs[CurrentJob+1]= tempJobID;
				changes=true;
			}
		}
	}while(changes==true);
}

void CompactRunningTask(){
	int changes=false;
	int CurrentJob;
	do{
		changes=false;
		for(CurrentJob=0;CurrentJob<9;CurrentJob++){
			if(RunningTask[CurrentJob]==-1 && RunningTask[CurrentJob+1]!=-1){
				int tempJobID;
				//Swap
				tempJobID=RunningTask[CurrentJob];
				RunningTask[CurrentJob]=RunningTask[CurrentJob+1];
				RunningTask[CurrentJob+1]= tempJobID;
				changes=true;
			}
		}
	}while(changes==true);
}
//printout the Job's ID child
void ExeChildren(int JOBID)
{
	char cmd[255];
	char str[5];
	FILE *reader;
	int i;
	int t_pid;
	char c_pid[255];

	//Convert job_id to pid, convert pid to string
	t_pid=JOBTable[JOBID].PID;
	sprintf(c_pid,"%d",t_pid);

	//Create the file list.txt which contains all the children of a job_id
	strcat(cmd, "ps -o pid,ppid -a | grep ");
	strcat(cmd, c_pid);
	strcat(cmd, " > list.txt");
	system(cmd);

	//Now just print out first 5 char of each line until the end of file
	reader=fopen("list.txt","r");

	fgets(str,255,reader);
	while(!feof(reader)){
		fgets(str,255,reader);
		for(i=0;i<5;i++){
			printf("%c",str[i]);
		}
		printf("\n");
	}
	//Done
}

//Pause the JOBID. Please remember to update the Status in JOBList
void pauseExe(int JOBID){

	int t_pid;
	t_pid = JOBTable[JOBID].PID;
	JOBTable[JOBID].Status = 0;
	kill(t_pid, SIGSTOP);

	return;
}

//unpause the Exe. Update status in JOBList
void unpauseExe(int JOBID){
    
	if (JOBTable[JOBID].PID == -1)
		{
		JOBTable[JOBID].Status = RUNNING;
	    RunEXE(JOBID);
		}
		
	else 
		{
		JOBTable[JOBID].Status = RUNNING;
		kill(JOBTable[JOBID].PID, SIGCONT);
		}

	return;
}





int MustWait(){
	
	if(wait_num>0 && NumRunningExe!=0) return true; //Still got task to wait 
	if(wait_num>0 && NumRunningExe==0) {wait_num=0; return false;} //Although wait_num>0, we have no more task running at all, reset the wait_num
	if(NumRunningExe==0) return false; // As long as no task, lets not wait
	if(wait_num<0){fprintf(stderr,"ERROR!!! wait_num is negative");	exit(666);} //Waitnum cant be negative. else print error
	return false;
}

int CheckJobStatus (int job_ID){
	int  cpid;
	pid_t wpid;
	int status;


	cpid = JOBTable[job_ID].PID;
	if(JOBTable[job_ID].PID==-1){
	printf("Exe either running +notupdated PID\n");
	return RUNNING;
	}
	wpid = waitpid(cpid, &status, WNOHANG | WUNTRACED | WCONTINUED); 
	
	if (wpid == -1) 
	{	
		//return 0;
		printf("F up error-JONID(%d)\n",job_ID);
		return;
		perror("waitpid");
		exit(EXIT_FAILURE); 
	}

	if (wpid == 0)
	{
		printf("no child has pid %d has yet changed state\n", cpid);
		return RUNNING;
	}

	if (WIFEXITED(status)) 
	{
		printf("exited, status=%d\n", WEXITSTATUS(status));
		JOBTable[job_ID].Status = TERMINATED;
		return TERMINATED;
	}

	

	return RUNNING;
}

int IsItInTopPriorityTask(int JOBID){
	int CurrentJob;
	for(CurrentJob=0;CurrentJob<10;CurrentJob++){
		if(TopPriorityTask[CurrentJob]==JOBID) return true;
	}
	return false;
}


int IsItInRunningTask(int JOBID){
	int CurrentJob;
	for(CurrentJob=0;CurrentJob<10;CurrentJob++){
		if(RunningTask[CurrentJob]==JOBID) return true;
	}
	return false;
}

void SetEnv(char *ENV_VAR, char *ENV_VALUE){

	int i,j,k;
	int length;
	int IsEmpty=0;
	int found;
	char NewEnv[255];

	length=strlen(ENV_VAR);

	//This is the NewEnv to be added/replaced
	strcpy(NewEnv,ENV_VAR);
	strcat(NewEnv,"=");
	strcat(NewEnv,ENV_VALUE);
	//printf("%s\n",NewEnv);

	//search GlobalEnv for ENV_VAR
	for(i=0;i<20;i++){
		found=strncmp(GlobalEnv[i],ENV_VAR,length);
		//printf("Found0=%d\n",found);
		//if found, replace ENV_VAR=OldValue with ENV_VAR=ENV_VALUE
		if(found=0){
			//printf("i=%d\n",i);
			//printf("found=%d\n",found);
			strcpy(GlobalEnv[i],NewEnv);
			return;
		}else{
			//If dont have, then find the closest empty slot
			for(j=0;j<20;j++){
				//if(GlobalEnv[j]=="\0"){
				//	IsEmpty=1;
				//}
				IsEmpty=strncmp(GlobalEnv[j],"\0",1);
				//printf("j=%d\n",j);
				//In the empty slot, add ENV_VAR=ENV_VALUE
				if(IsEmpty==0){
					strcpy(GlobalEnv[j],NewEnv);
					return;
				}
			}
		}
	}
return;
}


void UnsetEnv(char *ENV_VAR){
	int i,j;
	int length;
	int found=0;

	length=strlen(ENV_VAR);
	//printf("%d\n",length);
	//search GlobalEnv for ENV_VAR
	for(i=0;i<20;i++){
		//printf("Setpoint1\n");
		found=strncmp(GlobalEnv[i],ENV_VAR,length);
		//if found, empty that slot and return
		if(found=0){
			//printf("Setpoint2\n");
			strcpy(GlobalEnv[i-1],"\0");
			return;
		}
	}
	//If not found, do nothing... hehe...
return;
}

void RunEXE(int JOBID){
	int f;
	//Check if JOBID is paused, if it is, unpause it
	printf("RUNEXE(%d)\n",JOBID);
	f=fork();
		//If it is not paused, then run it.
		if(f >0 ){
			//parent running
			JOBTable[JOBID].PID=f;
			printf("Fork Successful\n");
			
		}else if(f==0){
			//child	running
			printf("child(%d) Running ",getpid());
			usleep(1000000);
		//	usleep(1000000);
			exit(6);
			//run the program
			//@todo uncomment below later
			//execle(JOBTable[JOBID].FileName, JOBTable[JOBID].Argument, JOBTable[JOBID].Environment);

			//Change status to running

		}else{
			//error
			perror("Fork Failed!! Nooooooo...");
			exit(1);
		}
	//end else
return;
}








